package net.orange.architecture.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * The exception dispathcer servlet.
 */ 
@WebServlet("/error")
public class ExceptionDispatcher extends HttpServlet {

	private static final long serialVersionUID = -3606626129140951424L;

	private static String DATABASE_ERROR_PAGE = "mgr/exception_db.jsf";

	private static String SECURITY_ERROR_PAGE = "mgr/noright.jsf";

	private static String OTHER_ERROR_PAGE = "mgr/exception.jsf";

	private static String MOBILE_ERROR_PAGE = "MobileError";

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest
	 * , javax.servlet.http.HttpServletResponse)
	 */
	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {

		// Get the exception object.
		Throwable throwable = (Throwable) req
				.getAttribute("javax.servlet.error.exception");
		
		// Get the error page according the exception type.
		String forward = getErrorPage(throwable);

	// Prepair the exception message
		StringWriter swriter = new StringWriter();
		PrintWriter pwriter = new PrintWriter(swriter);
		throwable.printStackTrace(pwriter);

		// Prepair the response object.
		req.setAttribute("exceptionMsg", throwable.getMessage());
		req.setAttribute("exceptionTrace", swriter.getBuffer().toString());
		req.setAttribute("exceptionClass", throwable.getClass().getName());

		if (includeSecurityException(throwable)) {
			req.setAttribute("blockURL", throwable.getMessage());
		}
		// foward the exception to error page
		ServletContext context = getServletContext();
		RequestDispatcher dispatcher = context.getRequestDispatcher("/"
				+ forward);
		dispatcher.forward(req, res);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest
	 * , javax.servlet.http.HttpServletResponse)
	 */
	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		doGet(req, res);
	}

	/**
	 * Get the page according the exception type.
	 * 
	 * @param throwable
	 *            The exception
	 * @return the error page
	 */
	private String getErrorPage(Throwable throwable) {
		String page = OTHER_ERROR_PAGE;

		if (includeSecurityException(throwable))
			page = SECURITY_ERROR_PAGE;
		else if (includeDatabaseException(throwable))
			page = DATABASE_ERROR_PAGE;
		else if (includeMobileException(throwable))
			page = MOBILE_ERROR_PAGE;
		else
			page = OTHER_ERROR_PAGE;

		return page;
	}

	/**
	 * Find whether include the security exception
	 * 
	 * @param e
	 *            The throwable
	 * @return Whether include the security exception
	 */
	private boolean includeSecurityException(Throwable e) {
		if (e != null)
			return e.toString().indexOf(
					"net.orange.architecture.exception.SecurityException") >= 0;
		else
			return false;
	}

	/**
	 * Find whether include the database exception
	 * 
	 * @param e
	 *            The throwable
	 * @return Whether include the database exception
	 */
	private boolean includeDatabaseException(Throwable e) {
		if (e != null)
			return e.toString().indexOf(
					"net.orange.architecture.exception.DatabaseException") >= 0;
		else
			return false;
	}

	/**
	 * Find whether include the database exception
	 * 
	 * @param e
	 *            The throwable
	 * @return Whether include the database exception
	 */
	private boolean includeMobileException(Throwable e) {
		if (e != null)
			return e.toString().indexOf(
					"com.imdroid.web.exception.MobileExpcetion") >= 0;
		else
			return false;
	}
}
